package com.ytktt.study.week9.task3.rpcfx.client.proxy;

import com.ytktt.study.week9.task3.rpcfx.annotation.RpcfxServiceConsumer;
import com.ytktt.study.week9.task3.rpcfx.api.RpcfxRequest;
import com.ytktt.study.week9.task3.rpcfx.api.RpcfxResponse;
import com.ytktt.study.week9.task3.rpcfx.client.transport.RpcfxTransport;
import com.ytktt.study.week9.task3.rpcfx.client.transport.netty.NettyTransport;
import com.ytktt.study.week9.task3.rpcfx.filter.RequestFilterChain;
import com.ytktt.study.week9.task3.rpcfx.registry.Registry;
import com.ytktt.study.week9.task3.rpcfx.utils.StringFormatUtils;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;

import java.lang.reflect.Method;

/**
 * TODO
 *
 * @author ytk
 */
@Slf4j
public class ByteBuddyRpcfxInterceptor {

    private final Registry registry;
    private final RequestFilterChain filterChain;

    public ByteBuddyRpcfxInterceptor(Registry registry, RequestFilterChain filterChain) {
        this.registry = registry;
        this.filterChain = filterChain;
    }

    @RuntimeType
    public Object intercept(@Origin Method method, @AllArguments Object[] params) throws Exception {
        RpcfxRequest request = new RpcfxRequest();
        Class<?> declaringClass = method.getDeclaringClass();
        RpcfxServiceConsumer rpcfxServiceConsumer = declaringClass.getAnnotation(RpcfxServiceConsumer.class);
        String serviceName = StringFormatUtils.lowerFirstLetter(declaringClass.getSimpleName());
        String group = rpcfxServiceConsumer.group();
        String version = rpcfxServiceConsumer.version();
        request.setServiceName(serviceName);
        request.setGroup(group);
        request.setVersion(version);
        request.setMethod(method.getName());
        request.setParams(params);

        if (!filterChain.filter(request)) {
            return null;
        }

        RpcfxTransport transport = new NettyTransport();
        String serviceUrl = this.registry.getServiceUrl(serviceName, group, version);
        RpcfxResponse response = transport.transport(request, serviceUrl, method.getReturnType());

        // 加filter地方之三
        // Student.setTeacher("cuijing");

        // 这里判断response.status, 处理异常
        // 考虑封装一个全局的RpcfxException

        Object result = response.getResult();
        // 清理客户端资源
        transport.clear();
        if (!response.isStatus()) {
            log.info(response.getMsg());
            throw new RuntimeException(response.getMsg());
        }
        return result;
    }
}
